home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 019a / opbgd113.zip / OPBIGED.PAS < prev   
Pascal/Delphi Source File  |  1991-10-21  |  64KB  |  2,382 lines

  1. {$A+,F+,O+,R-,S-,V-}
  2.  
  3. {$I OPDEFINE.INC}
  4.  
  5. {*********************************************************}
  6. {*                   OPBIGED.PAS 1.13                    *}
  7. {*        Copyright (c) TurboPower Software 1991.        *}
  8. {*                 All rights reserved.                  *}
  9. {*********************************************************}
  10.  
  11. unit OpBigEd;
  12.  
  13. {$IFNDEF UseMouse}
  14.   {$UNDEF UseDrag}
  15. {$ENDIF}
  16.  
  17. interface
  18.  
  19. uses
  20.   DOS,
  21.   OpInline,
  22.   OpRoot,
  23.   OpDos,
  24.   OpString,
  25.   OpAsciiZ,
  26.   OpCrt,
  27. {$IFDEF UseMouse}
  28.   OpMouse,
  29. {$ENDIF}
  30.   OpCmd,
  31. {$IFDEF UseDrag}
  32.   OpDrag,
  33. {$ENDIF}
  34.   OpFrame,
  35.   OpWindow;
  36.  
  37. {$I OPBIGED.ICD}
  38.  
  39. const
  40.   AbsMaxAsciiZ : Integer = MaxInt;  {our absolute max line length}
  41.   MemSafetySize = 4096;             {minimum 4K heap safety pool}
  42.  
  43. const
  44.   beInsert         = $00000001;  {True if in insert mode}
  45.   beIndent         = $00000002;  {True if in auto-indent mode}
  46.   beReadOnly       = $00000004;  {True if in read-only mode}
  47.   beWordWrap       = $00000008;  {True if word wrap is on}
  48.   beDeleteJoins    = $00000010;  {True if <Del> can join lines}
  49.   beModified       = $00000020;  {True if edits have been made}
  50.   beIndentIsPara   = $00000040;  {indent starts paragraph?}
  51.   beMousePage      = $00000080;  {clicking on scroll bar scrolls by page}
  52.   beDeTab          = $00000100;  {expand tabs on reads?}                  {!!}
  53.   beEnTab          = $00000200;  {compress tabs on writes?}               {!!}
  54.   beMapCtrls       = $00000400;  {map control characters?}
  55.   beMakeBackups    = $00000800;  {make backup files?}
  56.   beReformatting   = $00001000;  {flag set while reformatting}
  57.   beNewFile        = $00002000;  {new file loaded}
  58.   beWrapAtLeft     = $00004000;  {wrap to prev line on <Left> at column 1}
  59.   beReadPartial    = $00008000;  {allow partial reads if file too large?} {!!.13c}
  60.   beStripHigh      = $00010000;  {strip hi bits when reading a file}
  61.   beNoRepeatGlobal = $00020000;  {flag to not repeat global search}
  62.   beForceRedraw    = $00040000;  {force entire screen to be updated}      {!!}
  63.   beBlockOK        = $00080000;  {set if block is currently OK}           {!!}
  64.   beHighlightCurr  = $00100000;  {set if the current line is highlighted} {!!}
  65.   beColumnBlock    = $00200000;  {set if in column-block mode}            {!!}
  66.   beNoDispList     = $00400000;  {set to dispose list on call to Done}    {!!}
  67.   beInProcess      = $00800000;  {internal flag set while in Process}
  68.   beSmartTabs      = $01000000;  {smart tabs or fixed tabs?}
  69.   beSearching      = $02000000;  {flag set while searching}
  70.   beDragBlock      = $04000000;  {set if dragblocking is on}              {!!}
  71.   beHighlightOn    = $10000000;  {set if highlighting on in a search}
  72.   beHighlightBack  = $20000000;  {highlighting goes backwards?}
  73.   beMarkersOn      = $40000000;  {text markers visible?}
  74.   beBlockOn        = $80000000;  {block markers on?}
  75.  
  76.   DefBigEdOptions : LongInt = beInsert+beIndent+beDeleteJoins+beMapCtrls+
  77.                               beMousePage+beMakeBackups+beSmartTabs+beDeTab+
  78.                               beReadPartial+beForceRedraw;
  79.   BadBigEdOptions : LongInt = beModified+beReformatting+beSearching+beBlockOK+
  80.                               beHighlightOn+beHighlightBack+beInProcess+
  81.                               beDragBlock+beColumnBlock;
  82.  
  83. const
  84.   DefBlockIndent : Integer = 2;
  85.   DefTabSize : Integer = 8;
  86.   LPTNum : Char = '1';
  87.   WrapDelims : CharSet = [^I, ' ', '-'];
  88.   SpaceDelims : CharSet = [^I, ' '];
  89.   WordDelims : CharSet = [^I, ' '..'"', '.', ',', ':', ';', '?', '!',
  90.                           '*', '(', ')', '[', ']', '{', '}', '<', '>',
  91.                           '+', '-', '/', '\', '''', '$', '=', '^', '#'];
  92.  
  93.   MaxSearchLen = 30;              {Maximum length of search string}
  94.   MaxBlockIndent = 10;            {max indent level allowed}
  95.  
  96.   {search option characters}
  97.   MaxSearchOptions = 5;
  98.   beBackward  = 'B';
  99.   beNoCase    = 'U';
  100.   beGlobal    = 'G';
  101.   beNoConfirm = 'N';
  102.   beBlockOnly = 'L';
  103.  
  104.   {codes for yes-no functions}
  105.   beNo        = 0;
  106.   beYes       = 1;
  107.   beQuit      = 2;
  108.   beAll       = 3;
  109.  
  110. const
  111.   {the commands in this set are disallowed in read-only mode}
  112.   DisallowedInReadOnlyMode : set of Byte =
  113.    [ccChar, ccCtrlChar, ccSelect, ccInsertLine, ccBack, ccDel, ccRestore,
  114.     ccDelEol, ccDelLine, ccDelWord, ccIns, ccTab, ccIndent, ccWordWrap,
  115.     ccReformatP, ccReformatG,
  116.     ccCenterLine, ccSaveFile, ccSaveNamed, ccSaveSwitch, ccSaveExit,
  117.     ccBlkCopy, ccBlkMove, ccBlkDelete, ccBlkUCase, ccBlkLCase,
  118.     ccBlkTCase, ccBlkIndent, ccBlkUnindent, ccBlkRead, ccReplace];
  119.  
  120. const
  121.   {I/O buffer size.  **Warning** these buffers are allocated on the stack!}
  122.   MaxFBuf = 8192;
  123.  
  124. type
  125.   {I/O buffer type}
  126.   IOBuf = Array[1..MaxFBuf] of Char;
  127.  
  128. type
  129.   {object for each line}
  130.   PLine = ^LineNode;
  131.   LineNode =
  132.     object(DoubleListNode)
  133.       St      : AsciiZPtr;
  134.       Len     : Integer;
  135.       Size    : Integer;
  136.       Blocked : Boolean;
  137.       NoTrim  : Boolean;
  138.  
  139.       constructor Init(S : AsciiZPtr);
  140.         {-init object}
  141.       destructor  Done; virtual;
  142.         {-dispose of it when finished}
  143.       function  lnUpdate(S : AsciiZPtr) : Word;
  144.         {-update the string pointer in the node to the new string}
  145.       function  lnLen : Integer;
  146.         {-return the length of the stored string}
  147.     end;
  148.  
  149.   {DoubleList with our special needs}
  150.   LineListPtr = ^LineList;
  151.   LineList =
  152.     object(DoubleList)
  153.       function Num(P : DoubleNodePtr) : Word;
  154.         {-return the position in the list of P, 0 if nil or not in list}
  155.       procedure Clean;
  156.         {-clear the list of all nodes}
  157.       function OfsLine(SP : PLine; OfsL : Integer) : PLine;
  158.         {-return PLine that is OfsL lines down from SP}
  159.     end;
  160.  
  161.   MarkerType = (mtBlockBegin, mtBlockEnd, mtMarker);
  162.   MarkerRec =
  163.     record
  164.       LP : PLine;
  165.       CP : Integer;
  166.     end;
  167.  
  168. const
  169.   MaxMarker = 3;
  170.  
  171. type
  172.   beChangeCaseType = (beToUpper, beToLower, beToggle);
  173.   beSearchType = (bescNone, bescSearch, bescReplace);
  174.   beCharType = (beAlpha, beWhite, bePunct);
  175.  
  176.   MarkerSet = Array[0..MaxMarker] of MarkerRec;
  177.  
  178.   beYesNoFunc = function(MsgCode : Word; Prompt : string;
  179.                          Default : Byte; QuitAndAll : Boolean) : Byte;
  180.   beEditFunc = function(MsgCode : Word; Prompt : string;
  181.                         ForceUp, TrimBlanks : Boolean;
  182.                         MaxLen : Byte; var S : string) : Boolean;
  183.   beGetFileFunc = function(MsgCode : Word; Prompt : string;
  184.                            ForceUp, TrimBlanks, Writing, MustExist : Boolean;
  185.                            MaxLen : Byte; DefExt : ExtStr;
  186.                            var S : string) : Boolean;
  187.   MStateRec =
  188.     record
  189.       LNum  : Integer;
  190.       CNum  : Integer;
  191.     end;
  192.  
  193.   StreamStateRec =
  194.     record
  195.       SSTNum     : Integer;
  196.       SSLOfs     : Integer;
  197.       SSCPos     : Integer;
  198.       SSCOfs     : Integer;
  199.  
  200.       SSOptions    : LongInt;
  201.       SSTabSize    : Integer;
  202.       SSBlockIndent: Integer;
  203.       SSMargin     : Integer;
  204.  
  205.       SSBlockBegin : MStateRec;
  206.       SSBlockEnd   : MStateRec;
  207.       SSMarkers    : Array[0..MaxMarker] of MStateRec;
  208.     end;
  209.  
  210.   BigEditorPtr = ^BigEditor;
  211.   beStatusProc = procedure(BEP : BigEditorPtr);
  212.   BigEditor =
  213.     object(CommandWindow)
  214.       LList    : LineListPtr;     {our list of lines}
  215.       TList    : LineListPtr;     {second list for block ops, etc.}
  216.  
  217.       Top      : PLine;           {top line of window}
  218.       TNum     : Integer;         {number of top line}
  219.       Cur      : PLine;           {current edit line}
  220.       LOfs     : Integer;         {offset of current line from Top (>= 0)}
  221.       CPos     : Integer;         {vert. cursor pos in window}
  222.       COfs     : Integer;         {cols offset of left window margin (>= 0)}
  223.  
  224.       Work     : AsciiZPtr;       {workspace vars}
  225.       Temp     : AsciiZPtr;
  226.  
  227.       beOptions     : LongInt;    {options longint}
  228.       beTabSize     : Byte;       {size of tabstops for fixed tabs}
  229.       beBlockIndent : Integer;    {block indention level}
  230.       beMargin      : Integer;    {right margin}
  231.       beLPTNum      : Char;       {printer port number (1-3)}
  232.  
  233.       beBlockBegin     : MarkerRec; {block and text markers}
  234.       beBlockEnd       : MarkerRec;
  235.       beMarkers        : MarkerSet;
  236.       beMarkerFlags    : Word;
  237.       beLastPosition   : MarkerRec;
  238.  
  239.  
  240.       beSearchSt   : string[MaxSearchLen];     {String to search for}
  241.       beReplaceSt  : string[MaxSearchLen];     {String to replace it with}
  242.       beOptionSt   : string[MaxSearchOptions]; {Search options}
  243.       beLastSearch : beSearchType;             {Type of last search operation}
  244.  
  245.       beStatus   : beStatusProc;             {our proc ptrs}
  246.       beYesNoP   : beYesNoFunc;
  247.       beEditP    : beEditFunc;
  248.       beGetFileP : beGetFileFunc;
  249.  
  250.       beCtrlColor, beCtrlMono           : Byte;   {our attributes}
  251.       beBlockColor, beBlockMono         : Byte;
  252.       beHighlightColor, beHighlightMono : Byte;
  253.       beMarkerColor, beMarkerMono       : Byte;
  254.  
  255.       TA, CA, BA, HA, MA : Byte;  {attribute bytes}
  256.  
  257.       bePathName : PathStr;       {pathname of current file}
  258.       beDefExt   : ExtStr;        {default extension}
  259.       SearchLine : PLine;         {used in text search/replace}
  260.       SaveCnt    : Word;          {used by UpdateScrollBars}
  261.  
  262.  
  263.       constructor Init(UX, UY, LX, LY : Byte);
  264.         {-initialize a BigEditor with default colors and options}
  265.       constructor InitCustom(UX, UY, LX, LY : Byte;
  266.                              var Colors : ColorSet;
  267.                              WinOpts : LongInt);
  268.         {-initialize a BigEditor with custom colors and options}
  269.       constructor InitDeluxe(UX, UY, LX, LY : Byte;
  270.                              var Colors : ColorSet;
  271.                              WinOpts : LongInt;
  272.                              WorkList : LineListPtr);
  273.         {-initialize a BigEditor using a already-allocated LineList}
  274.       destructor Done; virtual;
  275.         {-destroy object when done}
  276.  
  277.     {...public methods}
  278.       function  YesNo(MsgCode : Word; Prompt : string;
  279.                       Default : Byte; QuitAndAll : Boolean) : Byte; virtual;
  280.       function  Edit(MsgCode : Word; Prompt : string;
  281.                      ForceUp, TrimBlanks : Boolean;
  282.                      MaxLen : Byte; var S : string) : Boolean; virtual;
  283.       function  GetFile(MsgCode : Word; Prompt : string;
  284.                         ForceUp, TrimBlanks, Writing, MustExist : Boolean;
  285.                         MaxLen : Byte; DefExt : ExtStr;
  286.                         var S : string) : Boolean; virtual;
  287.  
  288.       procedure beOptionsOn(L : LongInt);
  289.         {-turn on one or more options}
  290.       procedure beOptionsOff(L : LongInt);
  291.         {-turn off one or more options}
  292.       function  beOptionsAreOn(L : LongInt) : Boolean;
  293.         {-true if all requested options are on}
  294.       procedure beToggleOption(L : LongInt);
  295.         {-invert the state of an option}
  296.  
  297.       procedure SetStatusProc(SP : beStatusProc);
  298.         {-set our status procedure}
  299.       procedure SetYesNoProc(YNF : beYesNoFunc);
  300.         {-set our Yes/No function}
  301.       procedure SetEditProc(EF : beEditFunc);
  302.         {-set our edit function}
  303.       procedure SetGetFileProc(GFF : beGetFileFunc);
  304.         {-set our function to get a filename}
  305.       procedure SetTextAttr(Color, Mono : Byte); virtual;
  306.         {-set attributes for normal text}
  307.       procedure SetBlockAttr(Color, Mono : Byte);
  308.         {-Set attributes for marked blocks}
  309.       procedure SetMarkerAttr(Color, Mono : Byte);
  310.         {-Set attributes for text markers and found text}
  311.       procedure SetHighlightAttr(Color, Mono : Byte);
  312.         {-Set attributes for highlighted current line}
  313.       procedure SetCtrlAttr(Color, Mono : Byte);
  314.         {-Set attributes for mapped control characters}
  315.       procedure SetBlockIndent(Indent : Integer);
  316.         {-Set block indentation level}
  317.       procedure SetDefaultExtension(DefExt : ExtStr);
  318.         {-Default extension to use when prompting for filenames}
  319.       procedure SetPrinter(LptNum : Integer);
  320.         {-Set printer (1-3)}
  321.  
  322.     {...virtual methods}
  323.       procedure SaveState(var S); virtual;
  324.         {-save the state of the current text stream into S}
  325.       procedure RestoreState(var S); virtual;
  326.         {-restore the state of the current stream from S}
  327.       procedure ReadFile(FName : string; var FSize : LongInt); virtual;
  328.         {-read a file into the editor}
  329.       procedure SaveFile; virtual;
  330.         {-save the current text stream to a file}
  331.       procedure SaveNamedFile; virtual;
  332.         {-save the stream under a different name}
  333.       procedure UpdateContents; virtual;
  334.         {-redraw the editor window}
  335.       procedure NewFilePrompted; virtual;
  336.         {-get a name for a new file and load it}
  337.       procedure ProcessSelf; virtual;
  338.         {-edit the text stream}
  339.  
  340.     {...private methods}
  341.       function  CurLine : PLine;
  342.       function  CurCol : Integer;
  343.       procedure SaveStatePrim(var S : StreamStateRec);
  344.       procedure RestoreStatePrim(var S : StreamStateRec);
  345.       function  Split(T, C : PLine) : Integer;
  346.       procedure ResetStream;
  347.       procedure beReadFilePrim(FName : string; var FSize : LongInt;
  348.                                ErrorPrefix : Word);
  349.       procedure beUpdateContents;
  350.       procedure AdjustCursorToWindow;
  351.       procedure OfsToPLine(P : PLine);
  352.       procedure SplitLinePrim(At : Integer);
  353.       function  SplitLine(P : PLine; At : Integer) : PLine;
  354.       function  LeadingWhite(P : PLine) : Integer;
  355.       procedure ChTopLine(Num : Integer);
  356.       procedure ChLine(Num : Integer);
  357.       procedure ChCursor(Num : Integer);
  358.       procedure CursorToHome;
  359.       procedure CursorToEnd;
  360.       procedure CursorToCol(Col : Integer);
  361.       procedure WordLeft;
  362.       procedure WordRight;
  363.       procedure TopOfFile;
  364.       procedure EndOfFile;
  365.       procedure GetWork(P : PLine);
  366.       procedure GetTemp(P : PLine);
  367.       procedure GetCurLine;
  368.       procedure GetCurLineTemp;
  369.       procedure HandleChar(Ch : Char);
  370.       procedure WordWrap(Src, OvrLap : AsciiZPtr; Margin : Integer);
  371.       procedure HandleCR(MoveCursor : Boolean);
  372.       procedure HandleBS;
  373.       procedure HandleTab;
  374.       procedure DelChar;
  375.       procedure DelEOL;
  376.       procedure DelWord;
  377.       procedure DelLine;
  378.       procedure GoToLinePtr(P : PLine);
  379.       procedure GoToLineNum(N : Integer);
  380.       procedure GoToLineCol(L, C : Integer);
  381.       procedure GoToMarker(var M : MarkerRec);
  382.       procedure DropMarker(L : PLine; C : Integer);
  383.       procedure SetTextMarker(Num : Integer);
  384.       function  MemForBlock : LongInt;
  385.       function  BlockContiguous : Boolean;
  386.       procedure ConnectBlocking;
  387.       procedure CleanBlocking;
  388.       function  LineInBlock(P : PLine) : Boolean;
  389.       function  CursorInBlock(ChkCol : Boolean) : Boolean;
  390.       procedure CharsInserted(P : PLine; At, Num : Integer);
  391.       procedure LineDeleted(P : PLine);
  392.       procedure LinesBroken(P : PLine; At : Integer);
  393.       procedure LinesJoined(P : PLine; At : Integer);
  394.       function  BlockToList(var L : LineList) : Boolean;
  395.       procedure BlockFromList(var L : LineList);
  396.       procedure MarkWordAsBlock;
  397.       function  DeleteBlockPrim : Boolean;
  398.       procedure CopyBlock;
  399.       procedure MoveBlock;
  400.       procedure DeleteBlock;
  401.       function  ReadBlockPrim(var Lst : LineList) : Boolean;
  402.       procedure ReadBlock;
  403.       procedure WriteBlock(ToPrn : Boolean);
  404.       procedure IndentBlock(Spaces : Integer);
  405.       procedure ChangeCaseBlock(CT : beChangeCaseType);
  406.       procedure CopyToClipboard(Cut : Boolean);
  407.       procedure PasteFromClipboard;
  408.       procedure TextSearch(Prompt : Boolean; SearchType : beSearchType);
  409.       procedure ReformatParagraph;
  410.       procedure ReformatGlobal;
  411.       procedure CenterLine;
  412.     {$IFDEF UseScrollBars}
  413.       procedure UpdateScrollBars;
  414.     {$ENDIF}
  415.     {$IFDEF UseMouse}
  416.       function ProcessMouseCommand(Cmd : Byte) : Boolean;
  417.     {$ENDIF}
  418.     end;
  419.  
  420.  
  421. var
  422. {$IFDEF UseDrag}
  423.   BigEditorCommands : DragProcessor;
  424. {$ELSE}
  425.   BigEditorCommands : CommandProcessor;
  426. {$ENDIF}
  427.  
  428.   ClipBoard : LineList;
  429.  
  430.  
  431. procedure NoBigEditorStatus(BEP : BigEditorPtr);
  432.  
  433.  
  434. implementation
  435.  
  436. {globals used in TextSearches}
  437. var
  438.   NoCase : Boolean;
  439.   Backwards : Boolean;
  440.   NoConfirm : Boolean;
  441.   BlockOnly : Boolean;
  442.   Global : Boolean;
  443.  
  444.   Status : Word;  {handy var for error checking}
  445.  
  446.  
  447.   procedure NoBigEditorStatus(BEP : BigEditorPtr);
  448.   begin
  449.     ;  {do-nothing proc}
  450.   end;
  451.  
  452.  
  453. {--- LineNode methods -------------------------------------------------------}
  454.  
  455.   constructor LineNode.Init(S : AsciiZPtr);
  456.   begin
  457.     if NOT DoubleListNode.Init then
  458.       Fail;
  459.  
  460.     Len := LenAsc(S^)+1;
  461.     if Len > AbsMaxAsciiZ then
  462.       Fail;
  463.  
  464.     Size := ((Len shr 3) + 1) shl 3;
  465.     if NOT GetMemCheck(St, Size) then
  466.       Fail;
  467.  
  468.     FillChar(St^, Size, 0);
  469.     MoveFast(S^, St^, Len);
  470.     Blocked := False;
  471.     NoTrim := False;
  472.   end;
  473.  
  474.   destructor LineNode.Done;
  475.   begin
  476.     FreeMemCheck(St, Size);
  477.     DoubleListNode.Done;
  478.   end;
  479.  
  480.   function LineNode.lnUpdate(S : AsciiZPtr) : Word;
  481.   var
  482.     X : Integer;
  483.     W : Word;
  484.   begin
  485.     W := LenAsc(S^);
  486.     if W > AbsMaxAsciiZ then begin
  487.       lnUpdate := ecLineTooLong;
  488.       exit;
  489.     end;
  490.  
  491.     X := (((W+1) shr 3) + 1) shl 3;
  492.     if Size <> X then begin
  493.       FreeMemCheck(St, Size);
  494.       Size := X;
  495.       if NOT GetMemCheck(St, Size) then begin
  496.         lnUpdate := ecOutOfMemory;
  497.         exit;
  498.       end;
  499.     end;
  500.     FillChar(St^, Size, 0);
  501.     Len := W;
  502.     MoveFast(S^, St^, Len);
  503.  
  504.     if not NoTrim then begin
  505.       while (Len > 0) and (St^[Len-1] = ' ') do begin
  506.         St^[Len-1] := #0;
  507.         Dec(Len);
  508.       end;
  509.       Inc(Len);
  510.     end;
  511.  
  512.     lnUpdate := 0;
  513.   end;
  514.  
  515.   function LineNode.lnLen : Integer;
  516.   begin
  517.     lnLen := Len-1;
  518.   end;
  519.  
  520. {--- LineList methods -------------------------------------------------------}
  521.  
  522.   function LineList.Num(P : DoubleNodePtr) : Word;
  523.   var W : Word;
  524.       N : DoubleNodePtr;
  525.   begin
  526.     Num := 0;
  527.     if P = nil then exit;
  528.     W := 1;
  529.     N := dlHead;
  530.     while (N <> P) do begin
  531.       Inc(W);
  532.       N := N^.dlNext;
  533.       if N = nil then exit;
  534.     end;
  535.     Num := W;
  536.   end;
  537.  
  538.   procedure LineList.Clean;
  539.   var N : DoubleNodePtr;
  540.       P : DoubleNodePtr;
  541.   begin
  542.     N := dlTail;
  543.     while N <> nil do begin
  544.       P := N^.dlPrev;
  545.       if OS(N).S >= OS(HeapOrg).S then
  546.         Dispose(N, Done)
  547.       else
  548.         N^.Done;
  549.       N := P;
  550.     end;
  551.     dlTail := nil;
  552.     dlHead := nil;
  553.     dlSize := 0;
  554.   end;
  555.  
  556.   function LineList.OfsLine(SP : PLine; OfsL : Integer) : PLine;
  557.   var
  558.     P : PLine;
  559.     W : Integer;
  560.   begin
  561.     P := SP;
  562.     W := 0;
  563.     while (P <> nil) and (W <> OfsL) do begin
  564.       P := PLine(P^.dlNext);
  565.       Inc(W);
  566.     end;
  567.     OfsLine := P;
  568.   end;
  569.  
  570. {--- BigEditor methods ------------------------------------------------------}
  571.  
  572.   constructor BigEditor.Init(UX, UY, LX, LY : Byte);
  573.   begin
  574.     if not BigEditor.InitCustom(UX, UY, LX, LY, DefaultColorSet, DefWindowOptions) then
  575.       Fail;
  576.   end;
  577.  
  578.   constructor BigEditor.InitCustom(UX, UY, LX, LY : Byte;
  579.                                    var Colors : ColorSet;
  580.                                    WinOpts : LongInt);
  581.   begin
  582.     if not CommandWindow.InitCustom(UX, UY, LX, LY, Colors, WinOpts,
  583.                                     BigEditorCommands, ucNone) then Fail;
  584.     New(LList, Init);
  585.     if LList = nil then begin
  586.       InitStatus := epFatal+ecOutOfMemory;
  587.       Fail;
  588.     end;
  589.  
  590.     New(TList, Init);
  591.     if TList = nil then begin
  592.       InitStatus := epFatal+ecOutOfMemory;
  593.       Dispose(LList,Done);
  594.       Fail;
  595.     end;
  596.  
  597.     if not GetMemCheck(Work, AbsMaxAsciiZ) then begin
  598.       InitStatus := epFatal+ecOutOfMemory;
  599.       Dispose(TList,Done);
  600.       Dispose(LList,Done);
  601.       Fail;
  602.     end;
  603.  
  604.     if not GetMemCheck(Temp, AbsMaxAsciiZ) then begin
  605.       InitStatus := epFatal+ecOutOfMemory;
  606.       FreeMemCheck(Work, AbsMaxAsciiZ);
  607.       Dispose(TList,Done);
  608.       Dispose(LList,Done);
  609.       Fail;
  610.     end;
  611.  
  612.     Str2Asc('', Work^);
  613.     New(Top, Init(Work));
  614.     if Top = nil then begin
  615.       InitStatus := epFatal+ecOutOfMemory;
  616.       FreeMemCheck(Temp, AbsMaxAsciiZ);
  617.       FreeMemCheck(Work, AbsMaxAsciiZ);
  618.       Dispose(TList,Done);
  619.       Dispose(LList,Done);
  620.       Fail;
  621.     end;
  622.     LList^.Append(Top);
  623.     ResetStream;
  624.  
  625.     beOptions := DefBigEdOptions;
  626.     beTabSize := DefTabSize;
  627.     beBlockIndent := DefBlockIndent;
  628.     beMargin := Width-3;
  629.     beLPTNum := LPTNum;
  630.  
  631.     FillChar(beBlockBegin, SizeOf(beBlockBegin), 0);
  632.     FillChar(beBlockEnd, SizeOf(beBlockEnd), 0);
  633.     FillChar(beMarkers, SizeOf(beMarkers), 0);
  634.     FillChar(beLastPosition, SizeOf(beLastPosition), 0);
  635.     beMarkerFlags := 0;
  636.  
  637.     beSearchSt   := '';
  638.     beReplaceSt  := '';
  639.     beOptionSt   := '';
  640.     beLastSearch := bescNone;
  641.  
  642.     beStatus    := NoBigEditorStatus;
  643.     @beYesNoP   := nil;
  644.     @beEditP    := nil;
  645.     @beGetFileP := nil;
  646.  
  647.     bePathName := '';
  648.     beDefExt := '';
  649.     SaveCnt := $FFFF;
  650.  
  651.     with Colors do begin
  652.       beCtrlColor := CtrlColor;
  653.       beCtrlMono  := CtrlMono;
  654.       beBlockColor := BlockColor;
  655.       beBlockMono  := BlockMono;
  656.       beMarkerColor := MarkerColor;
  657.       beMarkerMono  := MarkerMono;
  658.       beHighlightColor := HighlightColor;
  659.       beHighlightMono  := HighlightMono;
  660.     end;
  661.     TA := ColorMono(wTextColor, wTextMono);
  662.     CA := ColorMono(beCtrlColor, beCtrlMono);
  663.     BA := ColorMono(beBlockColor, beBlockMono);
  664.     MA := ColorMono(beMarkerColor, beMarkerMono);
  665.     HA := ColorMono(beHighlightColor, beHighlightMono);
  666.   end;
  667.  
  668.   constructor BigEditor.InitDeluxe(UX, UY, LX, LY : Byte;
  669.                                    var Colors : ColorSet;
  670.                                    WinOpts : LongInt;
  671.                                    WorkList : LineListPtr);
  672.   begin
  673.     if not CommandWindow.InitCustom(UX, UY, LX, LY, Colors, WinOpts,
  674.                                     BigEditorCommands, ucNone) then Fail;
  675.  
  676.     LList := WorkList;
  677.  
  678.     New(TList, Init);
  679.     if TList = nil then begin
  680.       InitStatus := epFatal+ecOutOfMemory;
  681.       Dispose(LList,Done);
  682.       Fail;
  683.     end;
  684.  
  685.     if not GetMemCheck(Work, AbsMaxAsciiZ) then begin
  686.       InitStatus := epFatal+ecOutOfMemory;
  687.       Dispose(TList,Done);
  688.       Fail;
  689.     end;
  690.  
  691.     if not GetMemCheck(Temp, AbsMaxAsciiZ) then begin
  692.       InitStatus := epFatal+ecOutOfMemory;
  693.       FreeMemCheck(Work, AbsMaxAsciiZ);
  694.       Dispose(TList,Done);
  695.       Fail;
  696.     end;
  697.  
  698.     Str2Asc('', Work^);
  699.     New(Top, Init(Work));
  700.     if Top = nil then begin
  701.       InitStatus := epFatal+ecOutOfMemory;
  702.       FreeMemCheck(Temp, AbsMaxAsciiZ);
  703.       FreeMemCheck(Work, AbsMaxAsciiZ);
  704.       Dispose(TList,Done);
  705.       Fail;
  706.     end;
  707.     LList^.Append(Top);
  708.     ResetStream;
  709.  
  710.     beOptions := DefBigEdOptions + beNoDispList;
  711.     beTabSize := DefTabSize;
  712.     beBlockIndent := DefBlockIndent;
  713.     beMargin := Width-3;
  714.     beLPTNum := LPTNum;
  715.  
  716.     FillChar(beBlockBegin, SizeOf(beBlockBegin), 0);
  717.     FillChar(beBlockEnd, SizeOf(beBlockEnd), 0);
  718.     FillChar(beMarkers, SizeOf(beMarkers), 0);
  719.     FillChar(beLastPosition, SizeOf(beLastPosition), 0);
  720.     beMarkerFlags := 0;
  721.  
  722.     beSearchSt   := '';
  723.     beReplaceSt  := '';
  724.     beOptionSt   := '';
  725.     beLastSearch := bescNone;
  726.  
  727.     beStatus    := NoBigEditorStatus;
  728.     @beYesNoP   := nil;
  729.     @beEditP    := nil;
  730.     @beGetFileP := nil;
  731.  
  732.     bePathName := '';
  733.     beDefExt := '';
  734.     SaveCnt := $FFFF;
  735.  
  736.     with Colors do begin
  737.       beCtrlColor := CtrlColor;
  738.       beCtrlMono  := CtrlMono;
  739.       beBlockColor := BlockColor;
  740.       beBlockMono  := BlockMono;
  741.       beMarkerColor := MarkerColor;
  742.       beMarkerMono  := MarkerMono;
  743.       beHighlightColor := HighlightColor;
  744.       beHighlightMono  := HighlightMono;
  745.     end;
  746.     TA := ColorMono(wTextColor, wTextMono);
  747.     CA := ColorMono(beCtrlColor, beCtrlMono);
  748.     BA := ColorMono(beBlockColor, beBlockMono);
  749.     MA := ColorMono(beMarkerColor, beMarkerMono);
  750.     HA := ColorMono(beHighlightColor, beHighlightMono);
  751.   end;
  752.  
  753.   destructor BigEditor.Done;
  754.   begin
  755.     FreeMemCheck(Temp, AbsMaxAsciiZ);
  756.     FreeMemCheck(Work, AbsMaxAsciiZ);
  757.     Dispose(TList,Done);
  758.  
  759.       {if "fast" Done, don't clean list...}
  760.     if not LongFlagIsSet(beOptions, beNoDispList) then
  761.       Dispose(LList,Done);
  762.  
  763.     CommandWindow.Done;
  764.   end;
  765.  
  766.   function BigEditor.CurLine : PLine;
  767.   begin
  768.     CurLine := LList^.OfsLine(Top, LOfs);
  769.   end;
  770.  
  771.   function BigEditor.CurCol : Integer;
  772.   begin
  773.     CurCol := CPos+COfs-1;
  774.   end;
  775.  
  776.   procedure BigEditor.SaveStatePrim(var S : StreamStateRec);
  777.   var
  778.     W : Word;
  779.     I : Integer;
  780.   begin
  781.     with S do begin
  782.       SSTNum := TNum;
  783.       SSLOfs := LOfs;
  784.       SSCPos := CPos;
  785.       SSCOfs := COfs;
  786.  
  787.       SSOptions := beOptions;
  788.       SSTabSize := beTabSize;
  789.       SSMargin := beMargin;
  790.       SSBlockIndent := beBlockIndent;
  791.  
  792.       with SSBlockBegin do begin
  793.         LNum := LList^.Num(beBlockBegin.LP);
  794.         CNum := beBlockBegin.CP;
  795.       end;
  796.  
  797.       with SSBlockEnd do begin
  798.         LNum := LList^.Num(beBlockEnd.LP);
  799.         CNum := beBlockEnd.CP;
  800.       end;
  801.  
  802.       for I := 0 to MaxMarker do
  803.         with SSMarkers[i] do begin
  804.           LNum := LList^.Num(beMarkers[i].LP);
  805.           CNum := beMarkers[i].CP;
  806.         end;
  807.     end;
  808.   end;
  809.  
  810.   procedure BigEditor.SaveState(var S);
  811.   begin
  812.     SaveStatePrim(StreamStateRec(S));
  813.   end;
  814.  
  815.   procedure BigEditor.RestoreStatePrim(var S : StreamStateRec);
  816.   var
  817.     P : PLine;
  818.     I : Integer;
  819.   begin
  820.     with S do begin
  821.       TNum := SSTNum;
  822.       Top  := PLine(LList^.Nth(TNum));
  823.       LOfs := SSLOfs;
  824.       CPos := SSCPos;
  825.       COfs := SSCOfs;
  826.  
  827.       beOptions := SSOptions;
  828.       beTabSize := SSTabSize;
  829.       beMargin := SSMargin;
  830.       beBlockIndent := SSBlockIndent;
  831.  
  832.       beBlockBegin.LP := PLine(LList^.Nth(SSBlockBegin.LNum));
  833.       beBlockBegin.CP := SSBlockBegin.CNum;
  834.  
  835.       beBlockEnd.LP := PLine(LList^.Nth(SSBlockEnd.LNum));
  836.       beBlockEnd.CP := SSBlockEnd.CNum;
  837.  
  838.       if BlockContiguous then
  839.         ConnectBlocking
  840.       else
  841.         ClearLongFlag(beOptions, beBlockOn);
  842.  
  843.       for I := 0 to MaxMarker do begin
  844.         beMarkers[i].LP := PLine(LList^.Nth(SSMarkers[i].LNum));
  845.         beMarkers[i].CP := SSMarkers[i].CNum;
  846.       end;
  847.  
  848.       SetLongFlag(beOptions, beForceRedraw+beNewFile);
  849.     end;
  850.   end;
  851.  
  852.   procedure BigEditor.RestoreState(var S);
  853.   begin
  854.     RestoreStatePrim(StreamStateRec(S));
  855.   end;
  856.  
  857.   function BigEditor.YesNo(MsgCode : Word; Prompt : string;
  858.                            Default : Byte; QuitAndAll : Boolean) : Byte;
  859.   begin
  860.     if @beYesNoP <> nil then
  861.       YesNo := beYesNoP(MsgCode, Prompt, Default, QuitAndAll)
  862.     else
  863.       YesNo := beQuit;
  864.   end;
  865.  
  866.   function BigEditor.Edit(MsgCode : Word; Prompt : string;
  867.                           ForceUp, TrimBlanks : Boolean;
  868.                           MaxLen : Byte; var S : string) : Boolean;
  869.   begin
  870.     if @beEditP = nil then
  871.       Edit := False
  872.     else
  873.       Edit := beEditP(MsgCode, Prompt, ForceUp, TrimBlanks, MaxLen, S);
  874.   end;
  875.  
  876.   function BigEditor.GetFile(MsgCode : Word; Prompt : string;
  877.                              ForceUp, TrimBlanks, Writing, MustExist : Boolean;
  878.                              MaxLen : Byte; DefExt : ExtStr;
  879.                              var S : string) : Boolean;
  880.   begin
  881.     if @beGetFileP = nil then
  882.       GetFile := False
  883.     else
  884.       GetFile := beGetFileP(MsgCode, Prompt, ForceUp, TrimBlanks,
  885.                             Writing, MustExist, MaxLen, DefExt, S);
  886.   end;
  887.  
  888.   procedure BigEditor.beOptionsOn(L : LongInt);
  889.   begin
  890.     SetLongFlag(beOptions, L and not BadBigEdOptions);
  891.   end;
  892.  
  893.   procedure BigEditor.beOptionsOff(L : LongInt);
  894.   begin
  895.     ClearLongFlag(beOptions, L and not BadBigEdOptions);
  896.   end;
  897.  
  898.   function BigEditor.beOptionsAreOn(L : LongInt) : Boolean;
  899.   begin
  900.     beOptionsAreOn := LongFlagIsSet(beOptions, L);
  901.   end;
  902.  
  903.   procedure BigEditor.SetTextAttr(Color, Mono : Byte);
  904.     {-change the default attribute for marked blocks}
  905.   begin
  906.     wTextColor := Color;
  907.     wTextMono := MapMono(Color, Mono);
  908.     TA := ColorMono(wTextColor, wTextMono);
  909.   end;
  910.  
  911.   procedure BigEditor.SetBlockAttr(Color, Mono : Byte);
  912.     {-change the default attribute for marked blocks}
  913.   begin
  914.     beBlockColor := Color;
  915.     beBlockMono := MapMono(Color, Mono);
  916.     BA := ColorMono(beBlockColor, beBlockMono);
  917.   end;
  918.  
  919.   procedure BigEditor.SetMarkerAttr(Color, Mono : Byte);
  920.     {-change the default attribute for text markers}
  921.   begin
  922.     beMarkerColor := Color;
  923.     beMarkerMono := MapMono(Color, Mono);
  924.     MA := ColorMono(beMarkerColor, beMarkerMono);
  925.   end;
  926.  
  927.   procedure BigEditor.SetHighlightAttr(Color, Mono : Byte);
  928.     {-change the default attribute for highlighting the current line}
  929.   begin
  930.     beHighlightColor := Color;
  931.     beHighlightMono := MapMono(Color, Mono);
  932.     HA := ColorMono(beHighlightColor, beHighlightMono);
  933.   end;
  934.  
  935.   procedure BigEditor.SetCtrlAttr(Color, Mono : Byte);
  936.     {-change the default attribute for mapped control characters}
  937.   begin
  938.     beCtrlColor := Color;
  939.     beCtrlMono := MapMono(Color, Mono);
  940.     CA := ColorMono(beCtrlColor, beCtrlMono);
  941.   end;
  942.  
  943.   procedure BigEditor.SetBlockIndent(Indent : Integer);
  944.     {-Set block indentation level}
  945.   begin
  946.     if Indent > MaxBlockIndent then
  947.       beBlockIndent := MaxBlockIndent
  948.     else if Indent > 0 then
  949.       beBlockIndent := Indent;
  950.   end;
  951.  
  952.   procedure BigEditor.SetDefaultExtension(DefExt : ExtStr);
  953.     {-Default extension to use when prompting for filenames}
  954.   begin
  955.     beDefExt := DefExt;
  956.   end;
  957.  
  958.   procedure BigEditor.SetPrinter(LptNum : Integer);
  959.   begin
  960.     if (LptNum < 1) or (LptNum > 3) then exit;
  961.     beLPTNum := Chr(LptNum + Ord('0'));
  962.   end;
  963.  
  964.   procedure BigEditor.beToggleOption(L : LongInt);
  965.   begin
  966.     if LongFlagIsSet(beOptions, L) then
  967.       ClearLongFlag(beOptions, L)
  968.     else
  969.       SetLongFlag(beOptions, L);
  970.   end;
  971.  
  972.   procedure BigEditor.SetStatusProc(SP : beStatusProc);
  973.   begin
  974.     beStatus := SP;
  975.   end;
  976.  
  977.   procedure BigEditor.SetYesNoProc(YNF : beYesNoFunc);
  978.   begin
  979.     beYesNoP := YNF;
  980.   end;
  981.  
  982.   procedure BigEditor.SetEditProc(EF : beEditFunc);
  983.   begin
  984.     beEditP := EF;
  985.   end;
  986.  
  987.   procedure BigEditor.SetGetFileProc(GFF : beGetFileFunc);
  988.   begin
  989.     beGetFileP := GFF;
  990.   end;
  991.  
  992.   {-----------------------------------------------------}
  993.  
  994.   function BigEditor.Split(T, C : PLine) : Integer;
  995.   var
  996.     I : Integer;
  997.   begin
  998.     I := 0;
  999.     while (C <> T) and (C <> nil) do begin
  1000.       C := PLine(C^.dlPrev);
  1001.       Inc(I);
  1002.     end;
  1003.     if C = nil then
  1004.       Split := 0
  1005.     else
  1006.       Split := I;
  1007.   end;
  1008.  
  1009.   procedure BigEditor.ResetStream;
  1010.   begin
  1011.     Top := PLine(LList^.Head);
  1012.     TNum := 1;
  1013.     LOfs := 0;
  1014.     CPos := 1;
  1015.     COfs := 0;
  1016.     SetLongFlag(beOptions, beForceRedraw);
  1017.   end;
  1018.  
  1019.   procedure BigEditor.beReadFilePrim(FName : string; var FSize : LongInt;
  1020.                                      ErrorPrefix : Word);
  1021.   label
  1022.     Skip;
  1023.   var
  1024.     Buf : IOBuf;
  1025.     F : Text;
  1026.     P : PLine;
  1027.     I : Integer;
  1028.   begin
  1029.     if cwGetLastError <> 0 then
  1030.       Exit;
  1031.  
  1032.     if beDefExt <> '' then
  1033.       FName := DefaultExtension(FName, beDefExt);
  1034.  
  1035.     Assign(F, FName);
  1036.     SetTextBuf(F, Buf, MaxFBuf);
  1037.     Reset(F);
  1038.     I := IoResult;
  1039.     if I = ecFileNotFound then
  1040.       {not found--a new file}
  1041.       FSize := 0
  1042.     else begin
  1043.       if I = ecPathNotFound then
  1044.         GotError(ErrorPrefix+I, emPathNotFound)
  1045.       else if I <> 0 then
  1046.         GotError(ErrorPrefix+I, emOpenError);
  1047.       if I <> 0 then
  1048.         Exit;
  1049.  
  1050.       {check the file size}
  1051.       FSize := TextFileSize(F);
  1052.     end;
  1053.  
  1054.     bePathName := StUpcase(FName);
  1055.     SetLongFlag(beOptions, beNewFile);
  1056.     LList^.Clean;
  1057.     if FSize = 0 then begin
  1058.       {empty or new file - fake one line}
  1059.       Str2Asc('', Work^);
  1060.       New(P, Init(Work));
  1061.       if P = nil then
  1062.         GotError(ErrorPrefix+ecOutOfMemory, emInsufficientMemory)
  1063.       else begin
  1064.         LList^.Append(P);
  1065.         ResetStream;
  1066.       end;
  1067.       exit;
  1068.     end;
  1069.  
  1070.     while not EOF(F) do begin
  1071.       if not ReadLnAsc(F, Work^) then begin
  1072.         GotError(ErrorPrefix+ecDiskRead, emReadError);
  1073.         goto Skip;
  1074.       end;
  1075.  
  1076.       New(P, Init(Work));
  1077.       if P = nil then begin
  1078.         GotError(ErrorPrefix+ecOutOfMemory, emInsufficientMemory);
  1079.         goto Skip;
  1080.       end;
  1081.  
  1082.       LList^.Append(P);
  1083.     end;
  1084.     ResetStream;
  1085.     ClearLongFlag(beOptions, beModified);
  1086.     SetLongFlag(beOptions, beForceRedraw);
  1087.  
  1088. Skip:
  1089.     Close(F); if IoResult = 0 then ;
  1090.   end;
  1091.  
  1092.   procedure BigEditor.ReadFile(FName : string; var FSize : LongInt);
  1093.   begin
  1094.     beReadFilePrim(FName, FSize, epFatal);
  1095.   end;
  1096.  
  1097.   procedure BigEditor.SaveFile;
  1098.   var
  1099.     Buf : IOBuf;
  1100.     F : Text;
  1101.     P : PLine;
  1102.     I : Word;
  1103.     B : Boolean;
  1104.  
  1105.     function MakeBakFile(NewName : string) : Boolean;
  1106.     var
  1107.       NF : file;
  1108.       BakName : string;
  1109.       I : Integer;
  1110.     begin
  1111.       MakeBakFile := False;
  1112.       if ExistFile(NewName) then begin
  1113.         BakName := ForceExtension(NewName, 'BAK');
  1114.         if NewName = BakName then begin
  1115.           GotError(epNonFatal+ecBadParam, 'Invalid file name');
  1116.           Exit;
  1117.         end;
  1118.  
  1119.         if ExistFile(BakName) then begin
  1120.           Assign(NF, BakName);
  1121.           System.Erase(NF);
  1122.           I := IoResult;
  1123.           if I <> 0 then begin
  1124.             GotError(epNonFatal+I, emNoMoreFiles);
  1125.             exit;
  1126.           end;
  1127.         end;
  1128.  
  1129.         Assign(NF, NewName);
  1130.         Rename(NF, BakName);
  1131.         I := IoResult;
  1132.         if I <> 0 then begin
  1133.           GotError(epNonFatal+I, emNoMoreFiles);
  1134.           exit;
  1135.         end;
  1136.       end;
  1137.       MakeBakFile := True;
  1138.     end;
  1139.  
  1140.   begin
  1141.     if bePathName = '' then
  1142.       Exit;
  1143.  
  1144.     {make a BAK file?}
  1145.     if LongFlagIsSet(beOptions, beMakeBackups) then
  1146.       if not MakeBakFile(bePathName) then exit;
  1147.  
  1148.     {open the file}
  1149.     Assign(F, bePathName);
  1150.     SetTextBuf(F, Buf, MaxFBuf);
  1151.     Rewrite(F);
  1152.     I := IoResult;
  1153.     if I <> 0 then begin
  1154.       GotError(epNonFatal+I, emOpenError);
  1155.       Close(F);
  1156.       I := IoResult;
  1157.       Exit;
  1158.     end;
  1159.  
  1160.     {write the stream to disk}
  1161.     P := PLine(LList^.Head);
  1162.     while P <> nil do begin
  1163.       B := WriteAsc(F, P^.St^);
  1164.       if not B then begin
  1165.         GotError(epNonFatal+ecDeviceWrite, emWriteError);
  1166.         Close(F);
  1167.         I := IoResult;
  1168.         Exit;
  1169.       end;
  1170.  
  1171.       Write(F, ^M^J);
  1172.       I := IoResult;
  1173.       if (I <> 0) then begin
  1174.         GotError(epNonFatal+I, emWriteError);
  1175.         Close(F);
  1176.         I := IoResult;
  1177.         Exit;
  1178.       end;
  1179.       P := PLine(P^.dlNext);
  1180.     end;
  1181.  
  1182.     {close the file}
  1183.     Close(F);
  1184.     I := IoResult;
  1185.     if I <> 0 then
  1186.       GotError(epNonFatal+I, emCloseError)
  1187.     else
  1188.       {reset modified flag}
  1189.       ClearLongFlag(beOptions, beModified);
  1190.   end;
  1191.  
  1192.   procedure BigEditor.SaveNamedFile;
  1193.   var
  1194.     OP : PathStr;
  1195.   begin
  1196.     OP := bePathName;
  1197.     if GetFile(epMessage+mcSaveAs, emBlockWrite, True, True, True, False,
  1198.                80, beDefExt, OP) then begin
  1199.       bePathName := OP;
  1200.       SaveFile;
  1201.       SetLongFlag(beOptions, beNewFile);
  1202.     end;
  1203.   end;
  1204.  
  1205.   procedure BigEditor.OfsToPLine(P : PLine);
  1206.   var
  1207.     L : PLine;
  1208.     I : Integer;
  1209.   begin
  1210.     L := Top;
  1211.     I := 0;
  1212.     while L <> P do begin
  1213.       L := PLine(L^.dlNext);
  1214.       Inc(I);
  1215.       if (I > Height) or (L = nil) then exit;
  1216.     end;
  1217.     LOfs := I;
  1218.     SetLongFlag(beOptions, beForceRedraw);
  1219.   end;
  1220.  
  1221.   procedure BigEditor.ChTopLine(Num : Integer);
  1222.   var
  1223.     I : Integer;
  1224.     P : PLine;
  1225.   begin
  1226.     if Num >= 0 then begin
  1227.       P := CurLine;
  1228.       for I := 1 to Num do
  1229.         if P^.dlNext <> nil then begin
  1230.           if Top^.dlNext <> nil then begin
  1231.             Top := PLine(Top^.dlNext);
  1232.             Inc(TNum);
  1233.           end;
  1234.           if P^.dlNext <> nil then
  1235.             P := PLine(P^.dlNext)
  1236.           else if LOfs > 0 then
  1237.             Dec(LOfs);
  1238.         end;
  1239.     end
  1240.     else for I := 1 to Abs(Num) do
  1241.       if Top^.dlPrev <> nil then begin
  1242.         Top := PLine(Top^.dlPrev);
  1243.         Dec(TNum);
  1244.       end;
  1245.     SetLongFlag(beOptions, beForceRedraw);
  1246.   end;
  1247.  
  1248.   procedure BigEditor.ChLine(Num : Integer);
  1249.   var
  1250.     I : Integer;
  1251.     P : PLine;
  1252.   begin
  1253.     if Num >= 0 then begin
  1254.       P := CurLine;
  1255.       for I := 1 to Num do
  1256.         if LOfs < (Height-1) then begin
  1257.           if P^.dlNext <> nil then begin
  1258.             P := PLine(P^.dlNext);
  1259.             Inc(LOfs);
  1260.           end;
  1261.         end
  1262.         else if P^.dlNext <> nil then
  1263.           ChTopLine(1);
  1264.     end
  1265.     else for I := 1 to Abs(Num) do
  1266.       if LOfs > 0 then
  1267.         Dec(LOfs)
  1268.       else
  1269.         ChTopLine(-1);
  1270.   end;
  1271.  
  1272.   procedure BigEditor.ChCursor(Num : Integer);
  1273.   var
  1274.     I : Integer;
  1275.   begin
  1276.     if Num >= 0 then begin
  1277.       for I := 1 to Num do
  1278.         if CPos < Width then
  1279.           Inc(CPos)
  1280.         else if (COfs+Width) < AbsMaxAsciiZ then begin
  1281.           Inc(COfs);
  1282.           SetLongFlag(beOptions, beForceRedraw);
  1283.         end;
  1284.     end
  1285.     else for I := 1 to Abs(Num) do
  1286.       if CPos > 1 then
  1287.         Dec(CPos)
  1288.       else if COfs > 0 then begin
  1289.         Dec(COfs);
  1290.         SetLongFlag(beOptions, beForceRedraw);
  1291.       end;
  1292.   end;
  1293.  
  1294.   procedure BigEditor.CursorToHome;
  1295.   begin
  1296.     CPos := 1;
  1297.     if COfs <> 0 then begin
  1298.       COfs := 0;
  1299.       SetLongFlag(beOptions, beForceRedraw);
  1300.     end;
  1301.   end;
  1302.  
  1303.   procedure BigEditor.CursorToEnd;
  1304.   begin
  1305.     Cur := CurLine;
  1306.     if Cur <> nil then begin
  1307.       CursorToHome;
  1308.       if Cur^.lnLen < Width then
  1309.         CPos := Cur^.Len
  1310.       else begin
  1311.         CPos := Width;
  1312.         COfs := Cur^.Len - Width;
  1313.         SetLongFlag(beOptions, beForceRedraw);
  1314.       end;
  1315.     end;
  1316.   end;
  1317.  
  1318.   procedure BigEditor.CursorToCol(Col : Integer);
  1319.   begin
  1320.     CursorToHome;
  1321.     ChCursor(Col);
  1322.   end;
  1323.  
  1324.   procedure BigEditor.GetWork(P : Pline);
  1325.   begin
  1326.     if P = nil then
  1327.       Str2Asc('', Work^)
  1328.     else
  1329.       MoveFast(P^.St^, Work^, P^.Len);
  1330.   end;
  1331.  
  1332.   procedure BigEditor.GetTemp(P : Pline);
  1333.   begin
  1334.     if P = nil then
  1335.       Str2Asc('', Temp^)
  1336.     else
  1337.       MoveFast(P^.St^, Temp^, P^.Len);
  1338.   end;
  1339.  
  1340.   procedure BigEditor.GetCurLine;
  1341.   begin
  1342.     Cur := CurLine;
  1343.     if Cur = nil then begin
  1344.       GotError(epFatal+ecStringNotFound, 'Line list corrupted');
  1345.       exit;
  1346.     end
  1347.     else
  1348.       GetWork(Cur);
  1349.   end;
  1350.  
  1351.   procedure BigEditor.GetCurLineTemp;
  1352.   begin
  1353.     Cur := CurLine;
  1354.     if Cur = nil then begin
  1355.       GotError(epFatal+ecStringNotFound, 'Line list corrupted');
  1356.       exit;
  1357.     end
  1358.     else
  1359.       GetTemp(Cur);
  1360.   end;
  1361.  
  1362.   procedure BigEditor.WordWrap(Src, Ovrlap : AsciiZPtr; Margin : Integer);
  1363.   var
  1364.     I : Integer;
  1365.   begin
  1366.     FillChar(Ovrlap^, AbsMaxAsciiZ, 0);
  1367.     I := Margin+1;
  1368.       {go backwards looking for chars}
  1369.     while (I > 0) and (not(Src^[i-1] in WrapDelims)) do Dec(I);
  1370.       {skip whitespace but not other delims}
  1371.     while (I > 0) and (Src^[i-1] in WrapDelims) do Dec(I);
  1372.     if (I = 0) or (I > Margin) then
  1373.         {no worddelims, return "margin" chars of Src with rest in Ovrlap}
  1374.       I := Margin;
  1375.     CopyAsc(Src^, I, AbsMaxAsciiZ, Ovrlap^);
  1376.     DeleteAsc(Src^, I, AbsMaxAsciiZ);
  1377.   end;
  1378.  
  1379.   procedure BigEditor.HandleChar(Ch : Char);
  1380.   label
  1381.     ErrorOut;
  1382.   var
  1383.     W, X : Integer;
  1384.     P : PLine;
  1385.   begin
  1386.     W := CurCol;
  1387.     GetCurLine;
  1388.     X := Cur^.lnLen;
  1389.  
  1390.     if W > X then begin
  1391.         {cursor past EOL, first pad to length}
  1392.       AscPad(Work^, W, Temp^);
  1393.  
  1394.         {add the char}
  1395.       ConcatStr(Temp^, Ch, Work^);
  1396.       Status := Cur^.lnUpdate(Work);
  1397.       if Status <> 0 then goto ErrorOut;
  1398.       CharsInserted(Cur, X, W-X);
  1399.     end
  1400.     else begin
  1401.         {at or before EOL}
  1402.       if LongFlagIsSet(beOptions, beInsert) then begin
  1403.           {insert the char at the cursor}
  1404.         InsertStr(Ch, Work^, W);
  1405.         CharsInserted(Cur, W, 1);
  1406.       end
  1407.       else begin
  1408.           {overwrite the char at the cursor with the new char}
  1409.         Work^[w] := Ch;
  1410.         if W = X then Work^[w+1] := #0;
  1411.       end;
  1412.           {update the string}
  1413.       Status := Cur^.lnUpdate(Work);
  1414.       if Status <> 0 then goto ErrorOut;
  1415.     end;
  1416.  
  1417.       {update cursor and flags}
  1418.     SetLongFlag(beOptions, beModified);
  1419.     ChCursor(1);
  1420.  
  1421.     if (Ch <> ' ') and
  1422.        (LongFlagIsSet(beOptions, beWordWrap)) and
  1423.        (CPos+COfs > beMargin) then begin
  1424.         {we need to wordwrap the string: first wrap the current line}
  1425.       WordWrap(Work, Temp, beMargin);
  1426.  
  1427.         {update the current line}
  1428.       Status := Cur^.lnUpdate(Work);
  1429.       if Status <> 0 then goto ErrorOut;
  1430.  
  1431.         {add our new line}
  1432.       new(P, Init(Temp));
  1433.       if P = nil then goto ErrorOut;
  1434.       LList^.Place(P, Cur);
  1435.       LinesBroken(Cur, beMargin);
  1436.  
  1437.         {trim leading whitespace from the overlap}
  1438.       X := LeadingWhite(P);
  1439.       if X > 0 then begin
  1440.         AscTrimLead(P^.St^, Temp^);
  1441.         Status := P^.lnUpdate(Temp);
  1442.         if Status <> 0 then goto ErrorOut;
  1443.         CharsInserted(P, 0, -X);
  1444.       end;
  1445.  
  1446.       if LongFlagIsSet(beOptions, beIndent) then begin
  1447.           {leftpad the overlap string to the indent}
  1448.         X := LeadingWhite(PLine(P^.dlPrev));
  1449.         if X > 0 then begin
  1450.           W := P^.lnLen+X;
  1451.           GetWork(P);
  1452.           AscLeftPad(Work^, W, Temp^);
  1453.           Status := P^.lnUpdate(Temp);
  1454.           if Status <> 0 then goto ErrorOut;
  1455.           CharsInserted(P, 0, X);
  1456.         end;
  1457.       end;
  1458.  
  1459.       ChLine(1);
  1460.       CursorToCol(P^.lnLen);
  1461.       SetLongFlag(beOptions, beForceRedraw);
  1462.     end;
  1463.     exit;
  1464.  
  1465. ErrorOut:
  1466.     if Status = 0 then Status := ecOutOfMemory;
  1467.     GotError(epNonFatal+Status, emInsufficientMemory);
  1468.   end;
  1469.  
  1470.   procedure BigEditor.SplitLinePrim(At : Integer);
  1471.     {-Splits Work^ at cursor, returning overhang in Temp^}
  1472.   begin
  1473.     if At > LenAsc(Work^) then begin
  1474.       AscPad(Work^, At, Work^);
  1475.       Str2Asc('', Temp^);
  1476.     end
  1477.     else begin
  1478.       CopyAsc(Work^, At, AbsMaxAsciiZ, Temp^);
  1479.       DeleteAsc(Work^, At, AbsMaxAsciiZ);
  1480.     end;
  1481.   end;
  1482.  
  1483.   function BigEditor.SplitLine(P : PLine; At : Integer) : PLine;
  1484.   var
  1485.     N : PLine;
  1486.   begin
  1487.     GetWork(P);
  1488.     SplitLinePrim(At);
  1489.     New(N, Init(Temp));
  1490.     SplitLine := N;
  1491.   end;
  1492.  
  1493.   function BigEditor.LeadingWhite(P : PLine) : Integer;
  1494.   var
  1495.     I, L : Integer;
  1496.   begin
  1497.     GetWork(P);
  1498.     L := P^.lnLen;
  1499.     I := 0;
  1500.     while I < L do begin
  1501.       if Work^[i] <> ' ' then begin
  1502.         LeadingWhite := I;
  1503.         exit;
  1504.       end;
  1505.       Inc(I);
  1506.     end;
  1507.     LeadingWhite := 0;
  1508.   end;
  1509.  
  1510.   procedure Bigeditor.HandleCR(MoveCursor : Boolean);
  1511.   var
  1512.     P : PLine;
  1513.     X : Integer;
  1514.     At : Integer;
  1515.   begin
  1516.     GetCurLine;
  1517.     At := CurCol;
  1518.     P := SplitLine(Cur, CurCol);
  1519.     if (P = nil) then begin
  1520.       GotError(epNonFatal+ecOutOfMemory, emInsufficientMemory);
  1521.       exit;
  1522.     end;
  1523.  
  1524.     LList^.Place(P, Cur);
  1525.     Status := Cur^.lnUpdate(Work);
  1526.     if Status <> 0 then begin
  1527.       GotError(epNonFatal+Status, emInsufficientMemory);
  1528.       exit;
  1529.     end;
  1530.  
  1531.     LinesBroken(Cur, At);
  1532.     if MoveCursor then begin
  1533.       ChLine(1);
  1534.       CursorToHome;
  1535.  
  1536.       if LongFlagIsSet(beOptions, beIndent) then begin
  1537.         X := LeadingWhite(PLine(P^.dlPrev));
  1538.         if X > 0 then begin
  1539.           GetTemp(P);
  1540.           AscLeftPad(Temp^, X+P^.lnLen, Work^);
  1541.           Status := P^.lnUpdate(Work);
  1542.           if Status <> 0 then begin
  1543.             GotError(epNonFatal+Status, emInsufficientMemory);
  1544.             exit;
  1545.           end;
  1546.           CharsInserted(P, 0, X);
  1547.         end;
  1548.         ChCursor(X);
  1549.       end;
  1550.     end;
  1551.     SetLongFlag(beOptions, beForceRedraw+beModified);
  1552.   end;
  1553.  
  1554.   procedure BigEditor.HandleTab;
  1555.   var
  1556.     L : PLine;
  1557.     P, I : Integer;
  1558.  
  1559.     function NextIndentCol(N : PLine; Start : Integer) : Integer;
  1560.     var
  1561.       Next : Integer;
  1562.       Len : Integer;
  1563.     begin
  1564.       GetTemp(N);
  1565.       Len := LenAsc(Temp^);
  1566.       Next := -1;
  1567.  
  1568.       if Len > 0 then begin
  1569.         if (Start < Len) then begin
  1570.           Next := Start;
  1571.           if (Temp^[Start] <> ' ') then
  1572.             {Start is in a word - advance to next blank}
  1573.             while (Next < Len) and (Temp^[Next] <> ' ') do
  1574.               Inc(Next);
  1575.  
  1576.           {In white space - advance to next non-blank}
  1577.           while (Next < Len) and (Temp^[Next] = ' ') do
  1578.             Inc(Next);
  1579.         end
  1580.         else
  1581.           {don't go anywhere}
  1582.           Next := Start;
  1583.       end;
  1584.  
  1585.       NextIndentCol := Next;
  1586.     end;
  1587.  
  1588.     function FollowingIndent : Word;
  1589.     var
  1590.       N : PLine;
  1591.     begin
  1592.       FollowingIndent := 0;
  1593.       N := Cur;
  1594.  
  1595.       if N^.dlNext <> nil then begin
  1596.         repeat
  1597.           N := PLine(N^.dlNext);
  1598.         until (N = nil) or (N^.lnLen <> 0);
  1599.         if N <> nil then
  1600.           FollowingIndent := NextIndentCol(N, 0);
  1601.       end;
  1602.     end;
  1603.  
  1604.     procedure InsertTab(Len, At : Integer);
  1605.     begin
  1606.       AscCharStr(' ', Len, Temp^);
  1607.       InsertAsc(Temp^, Work^, At);
  1608.       Status := Cur^.lnUpdate(Work);
  1609.       if Status <> 0 then begin
  1610.         GotError(epNonFatal+Status, emInsufficientMemory);
  1611.         exit;
  1612.       end;
  1613.       CursorToCol(At+Len);
  1614.       CharsInserted(Cur, Len, At);
  1615.     end;
  1616.  
  1617.   begin
  1618.     GetCurLine;
  1619.     P := CurCol;
  1620.  
  1621.     if LongFlagIsSet(beOptions, beSmartTabs) then begin
  1622.         {smart tab: first check previous line}
  1623.       if Cur = PLine(LList^.Head) then
  1624.         I := -1
  1625.       else
  1626.         I := NextIndentCol(PLine(Cur^.dlPrev), P);
  1627.  
  1628.       if I > P then
  1629.         InsertTab(I-P, P)
  1630.       else if (I < 0) or (P > Cur^.lnLen) then begin
  1631.           {check following line(s)}
  1632.         I := FollowingIndent;
  1633.         if I > P then
  1634.           InsertTab(I, P);
  1635.       end;
  1636.     end
  1637.     else begin
  1638.         {do a fixed tab}
  1639.       I := Pred(beTabSize - (P mod beTabSize));
  1640.       if I = 0 then I := beTabSize;
  1641.       InsertTab(I, P);
  1642.     end;
  1643.   end;
  1644.  
  1645.   procedure BigEditor.HandleBS;
  1646.   var
  1647.     W : Integer;
  1648.     P : PLine;
  1649.   begin
  1650.     W := CurCol;
  1651.     GetCurLine;
  1652.  
  1653.     if W > 0 then begin
  1654.       DeleteAsc(Work^, W-1, 1);
  1655.       Status := Cur^.lnUpdate(Work);
  1656.       if Status <> 0 then begin
  1657.         GotError(epNonFatal+Status, emInsufficientMemory);
  1658.         exit;
  1659.       end;
  1660.  
  1661.       ChCursor(-1);
  1662.       CharsInserted(Cur, W-1, -1);
  1663.       SetLongFlag(beOptions, beModified);
  1664.     end
  1665.     else if Cur^.dlPrev <> nil then begin
  1666.       P := PLine(Cur^.dlPrev);
  1667.       LinesJoined(Cur, P^.LnLen);
  1668.       LList^.Delete(Cur);
  1669.       W := LenAsc(P^.St^);
  1670.       ConcatAsc(P^.St^, Work^, Temp^);
  1671.       Status := P^.lnUpdate(Temp);
  1672.       if Status <> 0 then begin
  1673.         GotError(epNonFatal+Status, emInsufficientMemory);
  1674.         exit;
  1675.       end;
  1676.       ChLine(-1);
  1677.       CursorToCol(W);
  1678.       SetLongFlag(beOptions, beForceRedraw+beModified);
  1679.     end;
  1680.   end;
  1681.  
  1682.   procedure BigEditor.WordLeft;
  1683.   var
  1684.     I : Integer;
  1685.   begin
  1686.     I := CurCol;
  1687.     GetCurLine;
  1688.     if I = 0 then begin
  1689.       if Cur^.dlPrev <> nil then begin
  1690.         ChLine(-1);
  1691.         CursorToEnd;
  1692.       end;
  1693.       exit;
  1694.     end;
  1695.  
  1696.     if I > Cur^.lnLen then
  1697.       I := Cur^.lnLen
  1698.     else begin
  1699.       while (I > 0) and (Work^[i-1] in WordDelims) do Dec(I);
  1700.       while (I > 0) and not(Work^[i-1] in WordDelims) do Dec(I);
  1701.     end;
  1702.     CursorToCol(I);
  1703.   end;
  1704.  
  1705.   procedure BigEditor.WordRight;
  1706.   var
  1707.     I, L : Integer;
  1708.   begin
  1709.     I := CurCol;
  1710.     GetCurLine;
  1711.     L := Cur^.lnLen;
  1712.     if I >= L then begin
  1713.       ChLine(1);
  1714.       CursorToHome;
  1715.     end
  1716.     else begin
  1717.       while (I < L) and not(Work^[i] in WordDelims) do Inc(I);
  1718.       while (I < L) and (Work^[i] in WordDelims) do Inc(I);
  1719.       CursorToCol(I);
  1720.     end;
  1721.   end;
  1722.  
  1723.   procedure BigEditor.DelChar;
  1724.   var
  1725.     B : Boolean;
  1726.   begin
  1727.     GetCurLine;
  1728.     if CurCol >= Cur^.lnLen then begin
  1729.       if (LongFlagIsSet(beOptions, beDeleteJoins)) and (Cur^.dlNext <> nil) then begin
  1730.         AscPad(Work^, CurCol, Temp^);
  1731.  
  1732.         Cur^.NoTrim := True;
  1733.         Status := Cur^.lnUpdate(Temp);
  1734.         Cur^.NoTrim := False;
  1735.         if Status <> 0 then begin
  1736.           GotError(epNonFatal+Status, emInsufficientMemory);
  1737.           exit;
  1738.         end;
  1739.  
  1740.         GetTemp(PLine(Cur^.dlNext));
  1741.         ConcatAsc(Cur^.St^, Temp^, Work^);
  1742.         Status := Cur^.lnUpdate(Work);
  1743.         if Status <> 0 then begin
  1744.           GotError(epNonFatal+Status, emInsufficientMemory);
  1745.           exit;
  1746.         end;
  1747.         LinesJoined(PLine(Cur^.dlNext), Cur^.lnLen);
  1748.         LList^.Delete(Cur^.dlNext);
  1749.         SetLongFlag(beOptions, beForceRedraw+beModified);
  1750.       end;
  1751.       exit;
  1752.     end;
  1753.     DeleteAsc(Work^, CurCol, 1);
  1754.     Status := Cur^.lnUpdate(Work);
  1755.     if Status <> 0 then begin
  1756.       GotError(epNonFatal+Status, emInsufficientMemory);
  1757.       exit;
  1758.     end;
  1759.     CharsInserted(Cur, CurCol, -1);
  1760.     SetLongFlag(beOptions, beModified);
  1761.   end;
  1762.  
  1763.   procedure BigEditor.DelEOL;
  1764.   var
  1765.     I, L : Integer;
  1766.   begin
  1767.     GetCurLine;
  1768.     L := Cur^.lnLen;
  1769.     I := CurCol;
  1770.     DeleteAsc(Work^, I, AbsMaxAsciiZ);
  1771.     Status := Cur^.lnUpdate(Work);
  1772.     if Status <> 0 then begin
  1773.       GotError(epNonFatal+Status, emInsufficientMemory);
  1774.       exit;
  1775.     end;
  1776.     CharsInserted(Cur, I, -(L-I));
  1777.     SetLongFlag(beOptions, beModified);
  1778.   end;
  1779.  
  1780.   procedure BigEditor.DelWord;
  1781.   var
  1782.     I, N, L : Integer;
  1783.     B : Boolean;
  1784.     CT : beCharType;
  1785.  
  1786.     function ClassifyChar(C : Char) : beCharType;
  1787.     begin
  1788.       if C in SpaceDelims then
  1789.         ClassifyChar := beWhite
  1790.       else if C in WordDelims then
  1791.         ClassifyChar := bePunct
  1792.       else
  1793.         ClassifyChar := beAlpha;
  1794.     end;
  1795.  
  1796.   begin
  1797.     GetCurLine;
  1798.     I := CurCol;
  1799.     if I >= Cur^.lnLen then begin
  1800.         {if we're past EOL, call DelChar to merge the line}
  1801.       DelChar;
  1802.       exit;
  1803.     end;
  1804.  
  1805.     L := Cur^.lnLen;
  1806.     N := I;
  1807.     CT := ClassifyChar(Work^[i]);
  1808.     while (I < L) and (ClassifyChar(Work^[i]) = CT) do Inc(I);
  1809.     while (I < L) and (Work^[i] in SpaceDelims) do Inc(I);
  1810.  
  1811.     DeleteAsc(Work^, N, I-N);
  1812.     Status := Cur^.lnUpdate(Work);
  1813.     if Status <> 0 then begin
  1814.       GotError(epNonFatal+ecOutOfMemory, emInsufficientMemory);
  1815.       exit;
  1816.     end;
  1817.     CharsInserted(Cur, N, -(I-N));
  1818.     SetLongFlag(beOptions, beModified);
  1819.   end;
  1820.  
  1821.  
  1822.   procedure BigEditor.DelLine;
  1823.   begin
  1824.     GetCurLine;
  1825.     if Cur = PLine(LList^.Tail) then begin
  1826.       Str2Asc('', Work^);
  1827.       Status := Cur^.lnUpdate(Work);
  1828.       if Status <> 0 then begin
  1829.         GotError(epNonFatal+ecOutOfMemory, emInsufficientMemory);
  1830.         exit;
  1831.       end;
  1832.       LineDeleted(Cur);
  1833.       CPos := 1;
  1834.       COfs := 0;
  1835.     end
  1836.     else begin
  1837.       if Top = Cur then begin
  1838.         Top := PLine(Top^.dlNext);
  1839.         Inc(TNum);
  1840.       end;
  1841.       LineDeleted(Cur);
  1842.       LList^.Delete(Cur);
  1843.     end;
  1844.     CursorToHome;
  1845.     SetLongFlag(beOptions, beForceRedraw+beModified);
  1846.   end;
  1847.  
  1848.   procedure BigEditor.TopOfFile;
  1849.   begin
  1850.     Top := PLine(LList^.Head);
  1851.     TNum := 1;
  1852.     LOfs := 0;
  1853.     CursorToHome;
  1854.     SetLongFlag(beOptions, beForceRedraw);
  1855.   end;
  1856.  
  1857.   procedure BigEditor.EndOfFile;
  1858.   var
  1859.     I : Integer;
  1860.   begin
  1861.     Top := PLine(LList^.Tail);
  1862.     TNum := LList^.Size;
  1863.     LOfs := 0;
  1864.     for I := 1 to Height-1 do
  1865.       if Top^.dlPrev <> nil then begin
  1866.         Top := PLine(Top^.dlPrev);
  1867.         Dec(TNum);
  1868.         Inc(LOfs);
  1869.       end;
  1870.     CursorToEnd;
  1871.     SetLongFlag(beOptions, beForceRedraw);
  1872.   end;
  1873.  
  1874.   procedure BigEditor.GoToLinePtr(P : PLine);
  1875.   var
  1876.     I, N : Integer;
  1877.   begin
  1878.     if P = nil then exit;
  1879.     I := LList^.Num(P);
  1880.     if I = 0 then exit;
  1881.  
  1882.     Top := P;
  1883.     TNum := I;
  1884.     N := LOfs;
  1885.     for I := 1 to N do
  1886.       if Top^.dlPrev <> nil then begin
  1887.         Top := PLine(Top^.dlPrev);
  1888.         Dec(TNum);
  1889.       end
  1890.       else Dec(LOfs);
  1891.     SetLongFlag(beOptions, beForceRedraw);
  1892.   end;
  1893.  
  1894.   procedure BigEditor.GoToLineNum(N : Integer);
  1895.   var
  1896.     I, X : Integer;
  1897.     P : PLine;
  1898.   begin
  1899.     if (N < 1) or (N > LList^.Size) then exit;
  1900.     P := PLine(LList^.Nth(N));
  1901.     if P = nil then exit;
  1902.  
  1903.     Top := P;
  1904.     TNum := N;
  1905.     X := LOfs;
  1906.     for I := 1 to X do
  1907.       if Top^.dlPrev <> nil then begin
  1908.         Top := PLine(Top^.dlPrev);
  1909.         Dec(TNum);
  1910.       end
  1911.       else Dec(LOfs);
  1912.     SetLongFlag(beOptions, beForceRedraw);
  1913.   end;
  1914.  
  1915.   procedure BigEditor.GoToLineCol(L, C : Integer);
  1916.   begin
  1917.     GoToLineNum(L);
  1918.     CursorToCol(C-1);
  1919.   end;
  1920.  
  1921.   procedure BigEditor.DropMarker(L : PLine; C : Integer);
  1922.   begin
  1923.     with beLastPosition do begin
  1924.       LP := L;
  1925.       CP := C;
  1926.     end;
  1927.   end;
  1928.  
  1929.   procedure BigEditor.SetTextMarker(Num : Integer);
  1930.   var
  1931.     P : PLine;
  1932.   begin
  1933.     if Num <= MaxMarker then
  1934.       with beMarkers[Num] do begin
  1935.         P := CurLine;
  1936.         if (LP = P) and (CP = CPos+COfs) then begin
  1937.           LP := nil;
  1938.           ClearFlag(beMarkerFlags, 1 shl Num);
  1939.         end
  1940.         else begin
  1941.           LP := P;
  1942.           CP := CPos+COfs;
  1943.           SetFlag(beMarkerFlags, 1 shl Num);
  1944.         end;
  1945.         SetLongFlag(beOptions, beForceRedraw+beMarkersOn);
  1946.       end;
  1947.   end;
  1948.  
  1949.  
  1950.   {-----------------------------------------}
  1951.  
  1952.   {block, text search/replace and reformatting, and screen update stuff}
  1953. {$I OPBIGED.IN1}
  1954.  
  1955.   {-----------------------------------------}
  1956.  
  1957.   procedure BigEditor.ProcessSelf;
  1958.   var
  1959.     Fin : Boolean;
  1960.     B : Byte;
  1961.     S : String;
  1962.     I : Integer;
  1963.     SaveCurLine : PLine;
  1964.     SaveCurCol : Integer;
  1965.   begin
  1966.     if cwGetLastError <> 0 then begin
  1967.       cwCmd := ccError;
  1968.       Exit;
  1969.     end;
  1970.  
  1971.     Draw;
  1972.     if RawError <> 0 then exit;
  1973.  
  1974. {$IFDEF UseMouse}
  1975.     ShowMouse;
  1976. {$ENDIF}
  1977.  
  1978.     SetLongFlag(beOptions, beInProcess);
  1979.     DropMarker(CurLine, CurCol);
  1980.     Fin := False;
  1981.  
  1982.     with LList^ do repeat
  1983.         {draw the window}
  1984.       UpdateContents;
  1985.       GetNextCommand;
  1986.  
  1987.       if (LongFlagIsSet(beOptions, beReadOnly)) and (GetLastCommand in DisallowedInReadOnlyMode) then
  1988.         SetLastCommand(ccNone);
  1989.  
  1990.       if GetLastCommand = ccCtrlChar then begin
  1991.         if ColorMono(wTextColor, wTextMono) = ColorMono(beCtrlColor, beCtrlMono) then
  1992.           cwCmd := ccNone
  1993.         else begin
  1994.           BlockCursor;
  1995.           cwKey := (cwCmdPtr^.cpGetKey and $001F);
  1996.           case Chr(Lo(cwKey)) of
  1997.             ^M : SetLastCommand(ccSelect);
  1998.         ^J, ^Z : SetLastCommand(ccNone);
  1999.             else SetLastCommand(ccChar);
  2000.           end;
  2001.           if LongFlagIsSet(beOptions, beInsert) then FatCursor else NormalCursor;
  2002.         end;
  2003.       end;
  2004.  
  2005.       SaveCurLine := CurLine;
  2006.       SaveCurCol := CurCol;
  2007.  
  2008.       case GetLastCommand of
  2009.         ccNone:
  2010.           ; {ignore}
  2011.  
  2012.       {char-oriented ops:}
  2013.         ccChar:
  2014.           HandleChar(Chr(Lo(cwKey)));
  2015.  
  2016.         ccSelect:
  2017.           HandleCR(True);
  2018.  
  2019.         ccInsertLine:
  2020.           HandleCR(False);
  2021.  
  2022.         ccTab:
  2023.           HandleTab;
  2024.  
  2025.       {cursor motion ops:}
  2026.         ccLeft:
  2027.           ChCursor(-1);
  2028.  
  2029.         ccWordLeft:
  2030.           WordLeft;
  2031.  
  2032.         ccRight:
  2033.           ChCursor(1);
  2034.  
  2035.         ccWordRight:
  2036.           WordRight;
  2037.  
  2038.         ccHome:
  2039.           CursorToHome;
  2040.  
  2041.         ccEnd:
  2042.           CursorToEnd;
  2043.  
  2044.         ccUp:
  2045.           ChLine(-1);
  2046.  
  2047.         ccScrollUp:
  2048.           ChTopLine(-1);
  2049.  
  2050.         ccScreenTop:
  2051.           begin
  2052.             LOfs := 0;
  2053.             SetLongFlag(beOptions, beForceRedraw);
  2054.           end;
  2055.  
  2056.         ccDown:
  2057.           ChLine(1);
  2058.  
  2059.         ccScrollDn:
  2060.           ChTopLine(1);
  2061.  
  2062.         ccScreenBot:
  2063.           begin
  2064.             LOfs := Height-1;
  2065.             SetLongFlag(beOptions, beForceRedraw);
  2066.           end;
  2067.  
  2068.         ccPageUp:
  2069.           if Top = PLine(LList^.Head) then
  2070.             TopOfFile
  2071.           else
  2072.             ChTopLine(-(Height-1));
  2073.  
  2074.         ccPageDn:
  2075.           ChTopLine(Height-1);
  2076.  
  2077.         ccTopOfFile:
  2078.           TopOfFile;
  2079.  
  2080.         ccEndOfFile:
  2081.           EndOfFile;
  2082.  
  2083.         ccJmpLine:
  2084.           begin
  2085.             S := Long2Str(TNum+LOfs);
  2086.             if Edit(mcLineNumber, emLineNumber, True, True, 5, S) then
  2087.               if Str2Int(S, I) then
  2088.                 GoToLineNum(I);
  2089.           end;
  2090.  
  2091.         ccJmpBegin:
  2092.           if beBlockBegin.LP <> nil then begin
  2093.             GoToLineCol(LList^.Num(beBlockBegin.LP), beBlockBegin.CP);
  2094.             OfsToPLine(beBlockBegin.LP);
  2095.           end;
  2096.  
  2097.         ccJmpEnd:
  2098.           if beBlockEnd.LP <> nil then begin
  2099.             GoToLineCol(LList^.Num(beBlockEnd.LP), beBlockEnd.CP+1);
  2100.             OfsToPLine(beBlockEnd.LP);
  2101.           end;
  2102.  
  2103.         ccPrevPos:
  2104.           with beLastPosition do
  2105.           if LP <> nil then begin
  2106.             GoToLinePtr(LP);
  2107.             CursorToCol(CP);
  2108.             OfsToPLine(LP);
  2109.           end;
  2110.  
  2111.       {deletion ops}
  2112.         ccBack:
  2113.           HandleBS;
  2114.  
  2115.         ccDel:
  2116.           DelChar;
  2117.  
  2118.         ccDelWord:
  2119.           DelWord;
  2120.  
  2121.         ccDelEOL:
  2122.           DelEOL;
  2123.  
  2124.         ccDelLine:
  2125.           DelLine;
  2126.  
  2127.       {search/replace ops:}
  2128.         ccSearch:
  2129.           TextSearch(True, bescSearch);
  2130.  
  2131.         ccReplace:
  2132.           TextSearch(True, bescReplace);
  2133.  
  2134.         ccReSearch:
  2135.           TextSearch(False, bescSearch);
  2136.  
  2137.       {reformatting:}
  2138.         ccReformatP:
  2139.           ReformatParagraph;
  2140.  
  2141.         ccReformatG:
  2142.           ReformatGlobal;
  2143.  
  2144.         ccCenterLine:
  2145.           CenterLine;
  2146.  
  2147.       {block-oriented ops:}
  2148.         ccBlkBegin:
  2149.           with beBlockBegin do begin
  2150.             LP := CurLine;
  2151.             CP := CurCol;
  2152.             if BlockContiguous then begin
  2153.               ConnectBlocking;
  2154.               SetLongFlag(beOptions, beBlockOn);
  2155.             end
  2156.             else begin
  2157.               CleanBlocking;
  2158.               ClearLongFlag(beOptions, beBlockOn);
  2159.             end;
  2160.             SetLongFlag(beOptions, beForceRedraw);
  2161.           end;
  2162.  
  2163.         ccBlkEnd:
  2164.           with beBlockEnd do begin
  2165.             LP := CurLine;
  2166.             CP := CurCol;
  2167.             if LP^.lnLen < CP then
  2168.               CP := LP^.lnLen;
  2169.             if BlockContiguous then begin
  2170.               ConnectBlocking;
  2171.               SetLongFlag(beOptions, beBlockOn);
  2172.             end
  2173.             else begin
  2174.               CleanBlocking;
  2175.               ClearLongFlag(beOptions, beBlockOn);
  2176.             end;
  2177.             SetLongFlag(beOptions, beForceRedraw);
  2178.           end;
  2179.  
  2180.         ccBlkToggle:
  2181.           begin
  2182.             if BlockContiguous then
  2183.               beToggleOption(beBlockOn)
  2184.             else begin
  2185.               CleanBlocking;
  2186.               ClearLongFlag(beOptions, beBlockOn);
  2187.             end;
  2188.             SetLongFlag(beOptions, beForceRedraw);
  2189.           end;
  2190.  
  2191.         ccBlkWord:
  2192.           MarkWordAsBlock;
  2193.  
  2194.         ccBlkCopy:
  2195.           CopyBlock;
  2196.  
  2197.         ccBlkMove:
  2198.           MoveBlock;
  2199.  
  2200.         ccBlkDelete:
  2201.           DeleteBlock;
  2202.  
  2203.         ccBlkIndent:
  2204.           IndentBlock(beBlockIndent);
  2205.  
  2206.         ccBlkUnindent:
  2207.           IndentBlock(-beBlockIndent);
  2208.  
  2209.         ccBlkUCase:
  2210.           ChangeCaseBlock(beToUpper);
  2211.  
  2212.         ccBlkLCase:
  2213.           ChangeCaseBlock(beToLower);
  2214.  
  2215.         ccBlkTCase:
  2216.           ChangeCaseBlock(beToggle);
  2217.  
  2218.         ccBlkRead:
  2219.           ReadBlock;
  2220.  
  2221.         ccBlkWrite:
  2222.           WriteBlock(False);
  2223.  
  2224.         ccBlkPrint:
  2225.           WriteBlock(True);
  2226.  
  2227.       {clipboard ops:}
  2228.         ccCopyClip:
  2229.           CopyToClipboard(False);
  2230.  
  2231.         ccCutClip:
  2232.           CopyToClipboard(True);
  2233.  
  2234.         ccPasteClip:
  2235.           PasteFromClipboard;
  2236.  
  2237.       {text marker stuff:}
  2238.         ccMarkToggle:
  2239.           begin
  2240.             beToggleOption(beMarkersOn);
  2241.             SetLongFlag(beOptions, beForceRedraw);
  2242.           end;
  2243.  
  2244.         ccSetMark0..ccSetMark9:
  2245.           begin
  2246.             B := GetLastCommand - ccSetMark0;
  2247.             SetTextMarker(B);
  2248.           end;
  2249.  
  2250.         ccJmpMark0..ccJmpMark9:
  2251.           begin
  2252.             B := GetLastCommand - ccJmpMark0;
  2253.             if B <= MaxMarker then
  2254.               with beMarkers[b] do
  2255.                 if LP <> nil then begin
  2256.                   GoToLineCol(LList^.Num(LP), CP);
  2257.                   SetLongFlag(beOptions, beForceRedraw+beMarkersOn);
  2258.                 end;
  2259.           end;
  2260.  
  2261.       {file ops:}
  2262.         ccNewFile:
  2263.           NewFilePrompted;
  2264.  
  2265.         ccSaveFile:
  2266.           if bePathName <> '' then
  2267.             SaveFile;
  2268.  
  2269.         ccSaveNamed:
  2270.           if bePathName <> '' then
  2271.             SaveNamedFile;
  2272.  
  2273.         ccSaveSwitch:
  2274.           if bePathName <> '' then begin
  2275.             SaveFile;
  2276.             if cwGetLastError = 0 then begin
  2277.               beStatus(@self);
  2278.               NewFilePrompted;
  2279.             end;
  2280.           end;
  2281.  
  2282.         ccSaveExit:
  2283.           if bePathName <> '' then begin
  2284.             SaveFile;
  2285.             Fin := True;
  2286.           end;
  2287.  
  2288.       {$IFDEF UseMouse}
  2289.         ccMouseAuto,
  2290.         ccMouseDown,
  2291.         ccMouseSel :
  2292.           if cwCmdPtr^.MouseEnabled then
  2293.             Fin := ProcessMouseCommand(cwCmd);
  2294.       {$ENDIF}
  2295.  
  2296.       {other misc. operations:}
  2297.         ccIns:
  2298.           beToggleOption(beInsert);
  2299.  
  2300.         ccIndent:
  2301.           beToggleOption(beIndent);
  2302.  
  2303.         ccTabToggle:
  2304.           beToggleOption(beSmartTabs);
  2305.  
  2306.         ccWordWrap:
  2307.           beToggleOption(beWordWrap);
  2308.  
  2309.         ccRtMargin:
  2310.           begin
  2311.             S := Long2Str(beMargin);
  2312.             if Edit(mcRightMargin, emRightMargin, True, True, 5, S) then
  2313.               if Str2Int(S, I) then
  2314.                 if (I > 0) then
  2315.                   beMargin := I;
  2316.           end;
  2317.  
  2318.         ccTabSize:
  2319.           begin
  2320.             S := Long2Str(beTabSize);
  2321.             if Edit(mcTabSize, emTabSize, True, True, 3, S) then
  2322.               if Str2Int(S, I) then
  2323.                 if (I > 0) and (I <= 255) then
  2324.                   beTabSize := I;
  2325.           end;
  2326.  
  2327.         ccSetIndent:
  2328.           begin
  2329.             S := Long2Str(beBlockIndent);
  2330.             if Edit(mcIndentLevel, emIndentLevel, True, True, 3, S) then
  2331.               if Str2Int(S, I) then
  2332.                 if (I > 0) and (I <= 10) then
  2333.                   beBlockIndent := I;
  2334.           end;
  2335.  
  2336.         ccHelp :
  2337.           RequestHelp(wHelpIndex);
  2338.  
  2339.       {exit commands:}
  2340.         ccUser0..ccUser65335,
  2341.         ccAbandonFile,
  2342.         ccQuit:
  2343.           Fin := True;
  2344.  
  2345.         else if (cwCmd <= 255) and (GetExitCommandPtr <> nil) then
  2346.           {Possibly a special exit command defined by a derived object}
  2347.           Fin := (cwCmd in GetExitCommandPtr^);
  2348.       end;
  2349.  
  2350.       {fix beLastPosition if necessary}
  2351.       if beLastPosition.LP = nil then
  2352.         DropMarker(Top, 0)
  2353.       else case cwCmd of
  2354.         ccBlkCopy,
  2355.         ccBlkMove,
  2356.         ccBlkDelete,
  2357.         ccBlkRead :
  2358.           {do nothing} ;
  2359.         else
  2360.           if SaveCurLine <> CurLine then
  2361.             DropMarker(SaveCurLine, SaveCurCol);
  2362.       end;
  2363.  
  2364.     until Fin or (cwCmd = ccError);
  2365.     UpdateContents;
  2366.  
  2367. {$IFDEF UseMouse}
  2368.     HideMouse;
  2369. {$ENDIF}
  2370.     rwSaveWindowState;
  2371.     ClearLongFlag(beOptions, beInProcess);
  2372.   end;
  2373.  
  2374. begin
  2375.   {make sure we don't get too long a line}
  2376.   if MaxAsciiZ < AbsMaxAsciiZ then
  2377.     AbsMaxAsciiZ := MaxAsciiZ;
  2378.   Clipboard.Init;
  2379.   BigEditorCommands.Init(@BigEditorKeySet, BigEditorKeyMax);
  2380. end.
  2381.  
  2382.